home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 126-150 / disk_147 / src / echo.c < prev    next >
C/C++ Source or Header  |  1992-05-06  |  12KB  |  591 lines

  1. /*
  2.  *        Echo line reading and writing.
  3.  *
  4.  * Common routines for reading
  5.  * and writing characters in the echo line area
  6.  * of the display screen. Used by the entire
  7.  * known universe.
  8.  */
  9. /*
  10.  * The varargs lint directive comments are 0 an attempt to get lint to shup
  11.  * up about CORRECT usage of varargs.h.  It won't.
  12.  */
  13. #include    "def.h"
  14. #include    "key.h"
  15. #ifdef    LOCAL_VARARGS
  16. #include    "varargs.h"
  17. #else
  18. #include    <varargs.h>
  19. #endif
  20. #ifndef NO_MACRO
  21. #  include    "macro.h"
  22. #endif
  23.  
  24. static int    veread();
  25. VOID        ewprintf();
  26. static VOID    eformat();
  27. static VOID    eputi();
  28. static VOID    eputl();
  29. static VOID    eputs();
  30. static VOID    eputc();
  31. static int    complt();
  32.  
  33. int    epresf    = FALSE;        /* Stuff in echo line flag.    */
  34. /*
  35.  * Erase the echo line.
  36.  */
  37. VOID
  38. eerase() {
  39.     ttcolor(CTEXT);
  40.     ttmove(nrow-1, 0);
  41.     tteeol();
  42.     ttflush();
  43.     epresf = FALSE;
  44. }
  45.  
  46. /*
  47.  * Ask "yes" or "no" question.
  48.  * Return ABORT if the user answers the question
  49.  * with the abort ("^G") character. Return FALSE
  50.  * for "no" and TRUE for "yes". No formatting
  51.  * services are available. No newline required.
  52.  */
  53. eyorn(sp) char *sp; {
  54.     register int    s;
  55.  
  56. #ifndef NO_MACRO
  57.     if(inmacro) return TRUE;
  58. #endif
  59.     ewprintf("%s? (y or n) ", sp);
  60.     for (;;) {
  61.         s = getkey(FALSE);
  62.         if (s == 'y' || s == 'Y') return TRUE;
  63.         if (s == 'n' || s == 'N') return FALSE;
  64.         if (s == CCHR('G')) return ctrlg(FFRAND, 1);
  65.         ewprintf("Please answer y or n.  %s? (y or n) ", sp);
  66.     }
  67.     /*NOTREACHED*/
  68. }
  69.  
  70. /*
  71.  * Like eyorn, but for more important question. User must type either all of
  72.  * "yes" or "no", and the trainling newline.
  73.  */
  74. eyesno(sp) char *sp; {
  75.     register int    s;
  76.     char        buf[64];
  77.  
  78. #ifndef NO_MACRO
  79.     if(inmacro) return TRUE;
  80. #endif
  81.     s = ereply("%s? (yes or no) ", buf, sizeof(buf), sp);
  82.     for (;;) {
  83.         if (s == ABORT) return ABORT;
  84.         if (s != FALSE) {
  85. #ifndef NO_MACRO
  86.             if (macrodef) {
  87.                 LINE *lp = maclcur;
  88.  
  89.                 maclcur = lp->l_bp;
  90.                 maclcur->l_fp = lp->l_fp;
  91.                 free((char *)lp);
  92.             }
  93. #endif
  94.             if ((buf[0] == 'y' || buf[0] == 'Y')
  95.                 &&    (buf[1] == 'e' || buf[1] == 'E')
  96.                 &&    (buf[2] == 's' || buf[2] == 'S')
  97.                 &&    (buf[3] == '\0')) return TRUE;
  98.             if ((buf[0] == 'n' || buf[0] == 'N')
  99.                 &&    (buf[1] == 'o' || buf[0] == 'O')
  100.                 &&    (buf[2] == '\0')) return FALSE;
  101.         }
  102.         s = ereply("Please answer yes or no.  %s? (yes or no) ",
  103.                buf, sizeof(buf), sp);
  104.     }
  105.     /*NOTREACHED*/
  106. }
  107. /*
  108.  * Write out a prompt, and read back a
  109.  * reply. The prompt is now written out with full "ewprintf"
  110.  * formatting, although the arguments are in a rather strange
  111.  * place. This is always a new message, there is no auto
  112.  * completion, and the return is echoed as such.
  113.  */
  114. /*VARARGS 0*/
  115. ereply(va_alist)
  116. va_dcl
  117. {
  118.     va_list pvar;
  119.     register char *fp, *buf;
  120.     register int nbuf;
  121.     register int i;
  122.  
  123.     va_start(pvar);
  124.     fp = va_arg(pvar, char *);
  125.     buf = va_arg(pvar, char *);
  126.     nbuf = va_arg(pvar, int);
  127.     i = veread(fp, buf, nbuf, EFNEW|EFCR, &pvar);
  128.     va_end(pvar);
  129.     return i;
  130. }
  131.  
  132. /*
  133.  * This is the general "read input from the
  134.  * echo line" routine. The basic idea is that the prompt
  135.  * string "prompt" is written to the echo line, and a one
  136.  * line reply is read back into the supplied "buf" (with
  137.  * maximum length "len"). The "flag" contains EFNEW (a
  138.  * new prompt), an EFFUNC (autocomplete), or EFCR (echo
  139.  * the carriage return as CR).
  140.  */
  141. /* VARARGS 0 */
  142. eread(va_alist)
  143. va_dcl
  144. {
  145.     va_list pvar;
  146.     char *fp, *buf;
  147.     int nbuf, flag, i;
  148.     va_start(pvar);
  149.     fp   = va_arg(pvar, char *);
  150.     buf  = va_arg(pvar, char *);
  151.     nbuf = va_arg(pvar, int);
  152.     flag = va_arg(pvar, int);
  153.     i = veread(fp, buf, nbuf, flag, &pvar);
  154.     va_end(pvar);
  155.     return i;
  156. }
  157.  
  158. static veread(fp, buf, nbuf, flag, ap) char *fp; char *buf; va_list *ap; {
  159.     register int    cpos;
  160.     register int    i;
  161.     register int    c;
  162.  
  163. #ifndef NO_MACRO
  164.     if(inmacro) {
  165.         bcopy(maclcur->l_text, buf, maclcur->l_used);
  166.         buf[maclcur->l_used] = '\0';
  167.         maclcur = maclcur->l_fp;
  168.         return TRUE;
  169.     }
  170. #endif
  171.     cpos = 0;
  172.     if ((flag&EFNEW)!=0 || ttrow!=nrow-1) {
  173.         ttcolor(CTEXT);
  174.         ttmove(nrow-1, 0);
  175.         epresf = TRUE;
  176.     } else
  177.         eputc(' ');
  178.     eformat(fp, ap);
  179.     tteeol();
  180.     ttflush();
  181.     for (;;) {
  182.         c = getkey(FALSE);
  183.         if ((flag&EFAUTO) != 0 && (c == ' ' || c == CCHR('I'))) {
  184.             cpos += complt(flag, c, buf, cpos);
  185.             continue;
  186.         }
  187.         switch (c) {
  188.             case CCHR('J'):
  189.             c = CCHR('M');        /* and continue        */
  190.             case CCHR('M'):        /* Return, done.    */
  191.             if ((flag&EFFUNC) != 0) {
  192.                 if ((i = complt(flag, c, buf, cpos)) == 0)
  193.                     continue;
  194.                 if (i > 0) cpos += i;
  195.             }
  196.             buf[cpos] = '\0';
  197.             if ((flag&EFCR) != 0) {
  198.                 ttputc(CCHR('M'));
  199.                 ttflush();
  200.             }
  201. #ifndef NO_MACRO
  202.             if(macrodef) {
  203.                 LINE *lp;
  204.  
  205.                 if((lp = lalloc(cpos)) == NULL) return FALSE;
  206.                 lp->l_fp = maclcur->l_fp;
  207.                 maclcur->l_fp = lp;
  208.                 lp->l_bp = maclcur;
  209.                 maclcur = lp;
  210.                 bcopy(buf, lp->l_text, cpos);
  211.             }
  212. #endif
  213.             goto done;
  214.  
  215.             case CCHR('G'):        /* Bell, abort.        */
  216.             eputc(CCHR('G'));
  217.             (VOID) ctrlg(FFRAND, 0);
  218.             ttflush();
  219.             return ABORT;
  220.  
  221.             case CCHR('H'):
  222.             case CCHR('?'):        /* Rubout, erase.    */
  223.             if (cpos != 0) {
  224.                 ttputc('\b');
  225.                 ttputc(' ');
  226.                 ttputc('\b');
  227.                 --ttcol;
  228.                 if (ISCTRL(buf[--cpos]) != FALSE) {
  229.                     ttputc('\b');
  230.                     ttputc(' ');
  231.                     ttputc('\b');
  232.                     --ttcol;
  233.                 }
  234.                 ttflush();
  235.             }
  236.             break;
  237.  
  238.             case CCHR('X'):        /* C-X            */
  239.             case CCHR('U'):        /* C-U, kill line.    */
  240.             while (cpos != 0) {
  241.                 ttputc('\b');
  242.                 ttputc(' ');
  243.                 ttputc('\b');
  244.                 --ttcol;
  245.                 if (ISCTRL(buf[--cpos]) != FALSE) {
  246.                     ttputc('\b');
  247.                     ttputc(' ');
  248.                     ttputc('\b');
  249.                     --ttcol;
  250.                 }
  251.             }
  252.             ttflush();
  253.             break;
  254.  
  255.             case CCHR('W'):        /* C-W, kill to beginning of */
  256.                         /* previous word    */
  257.             /* back up to first word character or beginning */
  258.             while ((cpos > 0) && !ISWORD(buf[cpos - 1])) {
  259.                 ttputc('\b');
  260.                 ttputc(' ');
  261.                 ttputc('\b');
  262.                 --ttcol;
  263.                 if (ISCTRL(buf[--cpos]) != FALSE) {
  264.                     ttputc('\b');
  265.                     ttputc(' ');
  266.                     ttputc('\b');
  267.                     --ttcol;
  268.                 }
  269.             }
  270.             while ((cpos > 0) && ISWORD(buf[cpos - 1])) {
  271.                 ttputc('\b');
  272.                 ttputc(' ');
  273.                 ttputc('\b');
  274.                 --ttcol;
  275.                 if (ISCTRL(buf[--cpos]) != FALSE) {
  276.                     ttputc('\b');
  277.                     ttputc(' ');
  278.                     ttputc('\b');
  279.                     --ttcol;
  280.                 }
  281.             }
  282.             ttflush();
  283.             break;
  284.  
  285.             case CCHR('\\'):
  286.             case CCHR('Q'):        /* C-Q, quote next    */
  287.             c = getkey(FALSE);    /* and continue        */
  288.             default:            /* All the rest.    */
  289.             if (cpos < nbuf-1) {
  290.                 buf[cpos++] = (char) c;
  291.                 eputc((char) c);
  292.                 ttflush();
  293.             }
  294.         }
  295.     }
  296. done:    return buf[0] != '\0';
  297. }
  298.  
  299. /*
  300.  * do completion on a list of objects.
  301.  */
  302. static int complt(flags, c, buf, cpos)
  303. register char *buf;
  304. register int cpos;
  305. {
  306.     register LIST    *lh, *lh2;
  307.     int        i, nxtra;
  308.     int        nhits, bxtra;
  309.     int        wflag = FALSE;
  310.     int        msglen, nshown;
  311.     char        *msg;
  312.  
  313.     if ((flags&EFFUNC) != 0) {
  314.         buf[cpos] = '\0';
  315.         i = complete_function(buf, c);
  316.         if(i>0) {
  317.         eputs(&buf[cpos]);
  318.         ttflush();
  319.         return i;
  320.         }
  321.         switch(i) {
  322.         case -3:
  323.             msg = " [Ambiguous]";
  324.             break;
  325.         case -2:
  326.             i=0;
  327.             msg = " [No match]";
  328.             break;
  329.         case -1:
  330.         case 0:
  331.             return i;
  332.         default:
  333.             msg = " [Internal error]";
  334.             break;
  335.         }
  336.     } else {
  337.         if ((flags&EFBUF) != 0) lh = &(bheadp->b_list);
  338.         else panic("broken complt call: flags");
  339.  
  340.         if (c == ' ') wflag = TRUE;
  341.         else if (c != '\t' && c != CCHR('M')) panic("broken complt call: c");
  342.  
  343.         nhits = 0;
  344.         nxtra = HUGE;
  345.  
  346.         while (lh != NULL) {
  347.         for (i=0; i<cpos; ++i) {
  348.             if (buf[i] != lh->l_name[i])
  349.                 break;
  350.         }
  351.         if (i == cpos) {
  352.             if (nhits == 0)
  353.                 lh2 = lh;
  354.             ++nhits;
  355.             if (lh->l_name[i] == '\0') nxtra = -1;
  356.             else {
  357.                 bxtra = getxtra(lh, lh2, cpos, wflag);
  358.                 if (bxtra < nxtra) nxtra = bxtra;
  359.                 lh2 = lh;
  360.             }
  361.         }
  362.         lh = lh->l_next;
  363.         }
  364.         if (nhits == 0)
  365.         msg = " [No match]";
  366.         else if (nhits > 1 && nxtra == 0)
  367.         msg = " [Ambiguous]";
  368.         else {        /* Got a match, do it to it */
  369.         /*
  370.          * Being lazy - ought to check length, but all things
  371.          * autocompleted have known types/lengths.
  372.          */
  373.         if (nxtra < 0 && nhits > 1 && c == ' ') nxtra = 1;
  374.         for (i = 0; i < nxtra; ++i) {
  375.             buf[cpos] = lh2->l_name[cpos];
  376.             eputc(buf[cpos++]);
  377.         }
  378.         ttflush();
  379.         if (nxtra < 0 && c != CCHR('M')) return 0;
  380.         return nxtra;
  381.         }
  382.     }
  383.     /* Set up backspaces, etc., being mindful of echo line limit */
  384.     msglen = strlen(msg);
  385.     nshown = (ttcol + msglen + 2 > ncol) ?
  386.             ncol - ttcol - 2 : msglen;
  387.     eputs(msg);
  388.     ttcol -= (i = nshown);        /* update ttcol!        */
  389.     while (i--)            /* move back before msg        */
  390.         ttputc('\b');
  391.     ttflush();            /* display to user        */
  392.     i = nshown;
  393.     while (i--)            /* blank out    on next flush    */
  394.         eputc(' ');
  395.     ttcol -= (i = nshown);        /* update ttcol on BS's        */
  396.     while (i--)
  397.         ttputc('\b');        /* update ttcol again!        */
  398.     return 0;
  399. }
  400.  
  401. /*
  402.  * The "lp1" and "lp2" point to list structures. The
  403.  * "cpos" is a horizontal position in the name.
  404.  * Return the longest block of characters that can be
  405.  * autocompleted at this point. Sometimes the two
  406.  * symbols are the same, but this is normal.
  407.   */
  408. getxtra(lp1, lp2, cpos, wflag) register LIST *lp1, *lp2; register int wflag; {
  409.     register int    i;
  410.  
  411.     i = cpos;
  412.     for (;;) {
  413.         if (lp1->l_name[i] != lp2->l_name[i]) break;
  414.         if (lp1->l_name[i] == '\0') break;
  415.         ++i;
  416.         if (wflag && !ISWORD(lp1->l_name[i-1])) break;
  417.     }
  418.     return (i - cpos);
  419. }
  420.  
  421. /*
  422.  * Special "printf" for the echo line.
  423.  * Each call to "ewprintf" starts a new line in the
  424.  * echo area, and ends with an erase to end of the
  425.  * echo line. The formatting is done by a call
  426.  * to the standard formatting routine.
  427.  */
  428. /*VARARGS 0 */
  429. VOID
  430. ewprintf(va_alist)
  431. va_dcl
  432. {
  433.     va_list pvar;
  434.     register char *fp;
  435.  
  436. #ifndef NO_MACRO
  437.     if(inmacro) return;
  438. #endif
  439.     va_start(pvar);
  440.     fp = va_arg(pvar, char *);
  441.     ttcolor(CTEXT);
  442.     ttmove(nrow-1, 0);
  443.     eformat(fp, &pvar);
  444.     va_end(pvar);
  445.     tteeol();
  446.     ttflush();
  447.     epresf = TRUE;
  448. }
  449.  
  450. /*
  451.  * Printf style formatting. This is
  452.  * called by both "ewprintf" and "ereply" to provide
  453.  * formatting services to their clients. The move to the
  454.  * start of the echo line, and the erase to the end of
  455.  * the echo line, is done by the caller.
  456.  * Note: %c works, and prints the "name" of the character.
  457.  * %k prints the name of a key (and takes no arguments).
  458.  */
  459. static VOID
  460. eformat(fp, ap)
  461. register char *fp;
  462. register va_list *ap;
  463. {
  464.     register int c;
  465.     char    kname[NKNAME];
  466.     char    *keyname();
  467.     char    *cp;
  468.  
  469.     while ((c = *fp++) != '\0') {
  470.         if (c != '%')
  471.             eputc(c);
  472.         else {
  473.             c = *fp++;
  474.             switch (c) {
  475.             case 'c':
  476.                 (VOID) keyname(kname, va_arg(*ap, int));
  477.                 eputs(kname);
  478.                 break;
  479.  
  480.             case 'k':
  481.                 cp = kname;
  482.                 for(c=0; c < key.k_count; c++) {
  483.                     cp = keyname(cp, key.k_chars[c]);
  484.                     *cp++ = ' ';
  485.                 }
  486.                 *--cp = '\0';
  487.                 eputs(kname);
  488.                 break;
  489.  
  490.             case 'd':
  491.                 eputi(va_arg(*ap, int), 10);
  492.                 break;
  493.  
  494.             case 'o':
  495.                 eputi(va_arg(*ap, int), 8);
  496.                 break;
  497.  
  498.             case 's':
  499.                 eputs(va_arg(*ap, char *));
  500.                 break;
  501.  
  502.             case 'l':/* explicit longword */
  503.                 c = *fp++;
  504.                 switch(c) {
  505.                 case 'd':
  506.                     eputl((long)va_arg(*ap, long), 10);
  507.                     break;
  508.                 default:
  509.                     eputc(c);
  510.                     break;
  511.                 }
  512.                 break;
  513.  
  514.             default:
  515.                 eputc(c);
  516.             }
  517.         }
  518.     }
  519. }
  520.  
  521. /*
  522.  * Put integer, in radix "r".
  523.  */
  524. static VOID
  525. eputi(i, r)
  526. register int i;
  527. register int r;
  528. {
  529.     register int    q;
  530.  
  531.     if(i<0) {
  532.         eputc('-');
  533.         i = -i;
  534.     }
  535.     if ((q=i/r) != 0)
  536.         eputi(q, r);
  537.     eputc(i%r+'0');
  538. }
  539.  
  540. /*
  541.  * Put long, in radix "r".
  542.  */
  543. static VOID
  544. eputl(l, r)
  545. register long l;
  546. register int  r;
  547. {
  548.     register long    q;
  549.  
  550.     if(l < 0) {
  551.         eputc('-');
  552.         l = -l;
  553.     }
  554.     if ((q=l/r) != 0)
  555.         eputl(q, r);
  556.     eputc((int)(l%r)+'0');
  557. }
  558.  
  559. /*
  560.  * Put string.
  561.  */
  562. static VOID
  563. eputs(s)
  564. register char *s;
  565. {
  566.     register int    c;
  567.  
  568.     while ((c = *s++) != '\0')
  569.         eputc(c);
  570. }
  571.  
  572. /*
  573.  * Put character. Watch for
  574.  * control characters, and for the line
  575.  * getting too long.
  576.  */
  577. static VOID
  578. eputc(c)
  579. register char c;
  580. {
  581.     if (ttcol+2 < ncol) {
  582.         if (ISCTRL(c)) {
  583.             eputc('^');
  584.             c = CCHR(c);
  585.         }
  586.         ttputc(c);
  587.         ++ttcol;
  588.     }
  589. }
  590.  
  591.